package edu.uclmgmu.bacteriosec.domain;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Map;

import edu.uclmgmu.bacteriosec.gui.JFBacterioSecMain;

public class Executor implements Runnable {
	private String classPath;
	private String launchingClass;
	private String bootPath;
	private String aspectsJWeaverPath;
	private String workingPath;
	private boolean usingJUnit;
	private String[] outputText;
	private int returnValue;
	private JFBacterioSecMain window;
	private long timeOut;
	private String cadenaComando;

	/**
	 * 
	 * @param jfBacterioSecMain 
	 * @param bytesStreamsPath Folder the modified class files are locate
	 * @param classPath CLASSPATH required to execute the SUT
	 * @param timeOut 
	 * @param mainClass	full name of the launching class 
	 * @param workingDirectory Folder where the mainClass is located
	 */
	public Executor(JFBacterioSecMain window, String aspectsJWeaverPath, String classPath, String launchingClass, String bootPath, String workingPath, long timeOut) {
		this.window=window;
		this.aspectsJWeaverPath=aspectsJWeaverPath;
		this.classPath=classPath;
		this.launchingClass=launchingClass;
		this.bootPath=bootPath;
		this.workingPath=workingPath;
		this.timeOut=timeOut;
	}
	
	public void setUsingJUnit(boolean usingJUnit) {
		this.usingJUnit=usingJUnit;
	}
	
	public void setOutputText(String[] outputText) {
		this.outputText=outputText;
	}
	
	public int getReturnValue() {
		return this.returnValue;
	}
	
	public void run() {
		ArrayList<String> comandos=new ArrayList<String>();
		this.cadenaComando = buildCommandLine(comandos);
		System.out.println(cadenaComando);
		if (outputText[0]==null)
			outputText[0]="";
		ProcessBuilder pb=new ProcessBuilder(comandos);
		File f=new File(this.workingPath);
		pb.directory(f);
		try {
			pb.redirectErrorStream(false);			
			//Process p = pb.start();
			Runtime runtime = java.lang.Runtime.getRuntime();
			Process p=runtime.exec(cadenaComando);
			ProcessController pc=null;
			if (this.timeOut>0) {
				pc=new ProcessController(p, (long) (this.timeOut*1.10));
				Thread t=new Thread(pc);
				t.start();
			}
			p.waitFor();
			if (pc==null) {
				log(p);
				this.returnValue=p.exitValue(); 
			} else if (pc!=null && !pc.getDestroyed()) {
				log(p); 
				this.returnValue=p.exitValue();
			} else {
				this.returnValue=-2000;
				outputText[0]="Process destroyed";
			}
		} catch (Exception e) {
			e.printStackTrace();
			outputText[0]=e.toString();
			this.returnValue=-1000;
		}
	}

	protected String buildCommandLine(ArrayList<String> comandos) {
		comandos.add("java");
		String bootPath=System.getProperties().get("sun.boot.class.path").toString();
		if (this.bootPath!=null && this.bootPath.length()>0) {
			bootPath=this.bootPath + ":" + bootPath;
			comandos.add("-Dsun.boot.class.path=" +  bootPath);
		}
		if (this.aspectsJWeaverPath!=null)
			comandos.add("-javaagent:" + this.aspectsJWeaverPath);		
		comandos.add("-cp");
		comandos.add(this.classPath);
		if (usingJUnit)
			//comandos.add("org.junit.runner.JUnitCore");
			comandos.add("edu.uclmgmu.bacteriosec.domain.testCaseRunner.SingleJUnitTestRunner");
		comandos.add(launchingClass);
		
		String cadenaComando="";
		for (String cadena : comandos) {
			cadenaComando+=cadena + " ";
		}
		return cadenaComando;
	}
	
	private static int zzz=0;

	protected void log(Process p) throws IOException {
		BufferedReader brs = new BufferedReader(new InputStreamReader(p.getInputStream()));
		boolean posibleError=false;
		int cont=0;
		String linea;
		do {
			System.out.println(zzz++);
			linea=brs.readLine();
			if (linea==null && cont==0)
				posibleError=true;
			else if (linea!=null) {
				cont++;
				linea="\t\t\t\t" + linea + "\n";
				this.outputText[0]+=linea;
			}
		} while (linea!=null);
		if (posibleError) {
			this.outputText[0]=this.cadenaComando + "\n";
			brs = new BufferedReader(new InputStreamReader(p.getErrorStream()));
			do {
				System.out.println(zzz++);
				linea=brs.readLine();
				if (linea!=null) {
					linea="\t\t\t\t" + linea + "\n";
					this.outputText[0]+=linea;
				}
			} while (linea!=null);
		}
	}
}
